package com.devunion.bogdan.view.project;

import com.devunion.bogdan.model.project.*;
import com.devunion.bogdan.model.UserManager;
import com.devunion.bogdan.view.actions.TreePopupActionManager;
import com.devunion.bogdan.view.project.actions.AbstractProjectAction;
import com.devunion.bogdan.view.project.actions.AddPageAction;
import com.devunion.bogdan.view.project.actions.RemovePageAction;
import com.devunion.bogdan.view.event.ProjectTreeBuilderListener;
import com.devunion.bogdan.view.event.ProjectTreeBuilderEvent;

import javax.swing.*;
import javax.swing.event.EventListenerList;
import javax.swing.tree.TreePath;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.event.MouseEvent;
import java.awt.event.MouseAdapter;
import java.awt.*;
import java.net.URL;

import org.swixml.SwingEngine;
import org.apache.log4j.Logger;

/**
 * @author Viktar Liaskovich
 */
public class ProjectTreeBuilder {
    private static Logger log = Logger.getLogger(ProjectTreeBuilder.class);
    private static ProjectTreeBuilder instance;
    private JPopupMenu popupMenu;

    protected EventListenerList listenerList = new EventListenerList();

    public static ProjectTreeBuilder getInstance() {
        if (instance == null) {
            instance = new ProjectTreeBuilder();
        }

        return instance;
    }

    private ProjectTreeBuilder() {
        SwingEngine se = new SwingEngine(TreePopupActionManager.getInstance());

        URL popupDefinition = ProjectTreeBuilder.class.getResource("/com/devunion/bogdan/conf/tree-popup.xml");

        try {
            popupMenu = (JPopupMenu) se.render(popupDefinition);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            e.printStackTrace();
        }
    }

    public JTree buildProjectTree(final Project project) {
        final JTree projectTree = new DefaultProjectTree(project);

        projectTree.add(popupMenu);

        projectTree.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent evt) {
                if (evt.getButton() == MouseEvent.BUTTON3) {
                    TreePath closestPathForLocation = projectTree.getClosestPathForLocation(evt.getX(), evt.getY());
                    projectTree.setSelectionPath(closestPathForLocation);
                }

                if (evt.isPopupTrigger()) {
                    updatePopup(projectTree);
                    popupMenu.show(evt.getComponent(), evt.getX(), evt.getY());
                }
            }

            public void mouseReleased(MouseEvent evt) {
                if (evt.isPopupTrigger()) {
                    updatePopup(projectTree);
                    popupMenu.show(evt.getComponent(), evt.getX(), evt.getY());
                }
            }

            public void mouseClicked(MouseEvent e) {
                if (isOpenEditorTrigger(e)) {
                    Page Page = (Page) ((PageNode) projectTree.getLastSelectedPathComponent()).getUserObject();
                    if (isOpened(project, projectTree)) {
//                        project.setActiveFile(Page);
                    } else {
//                        project.openFile(Page);
                    }
                }
            }
        });

        fireOnTreeCreatedEvent(new ProjectTreeBuilderEvent(this, project, projectTree));

        // This is required when we are opening already existing project
        project.resendEvents();

        return projectTree;
    }

    private void updatePopup(JTree projectTree) {
        Object userObject = ((AbstractEntryNode) projectTree.getLastSelectedPathComponent()).getUserObject();

        User u = UserManager.getInstance().getUser();

        if (userObject instanceof Project) {  // Root
            for (Component m : popupMenu.getComponents()) {
                if (m instanceof JMenuItem) {
                    Action action = ((JMenuItem) m).getAction();
                    if (action instanceof AddPageAction || action instanceof RemovePageAction) {
                        action.setEnabled(false);
                    } else {
                        if (u != null && !u.isNormal()) {
                        action.setEnabled(true);
                    }
                }
            }
            }
        } else if (userObject instanceof Paper) {
            Paper e = (Paper) userObject;

            for (Component m : popupMenu.getComponents()) {
                if (m instanceof JMenuItem) {
                    Action action = ((JMenuItem) m).getAction();
                    if (action instanceof AbstractProjectAction) {
                        action.setEnabled(((AbstractProjectAction) action).isApplicable(e));
                    }
                }
            }
        } else if (userObject instanceof Page) {
            Page e = (Page) userObject;

            for (Component m : popupMenu.getComponents()) {
                if (m instanceof JMenuItem) {
                    Action action = ((JMenuItem) m).getAction();
                    if (action instanceof RemovePageAction) {

                        if (u == null || u.isNormal()) {
                            action.setEnabled(false);
                        } else {
                            final Project p = ProjectManager.getInstance().getCurrentProject();
                            action.setEnabled(u.isAdmin() || u.isExpert() && u.getLogin().equals(p.getOwner().getLogin()));
                        }
                    } else {
                        action.setEnabled(false);
                    }
                }
            }
        }

        popupMenu.show();
    }


    public void destroyProjectTree(JTree projectTree) {
        Project project = (Project) ((DefaultMutableTreeNode) projectTree.getModel().getRoot()).getUserObject();

        projectTree.remove(popupMenu);
        popupMenu.hide();

        fireOnTreeDestroyedEvent(new ProjectTreeBuilderEvent(this, project, projectTree));

        projectTree = null;
    }

    private boolean isOpened(Project project, JTree jTreeProject) {
        return false;
//        return project.isOpened((Page) ((PageNode) jTreeProject.getLastSelectedPathComponent()).getUserObject());
    }

    private boolean isOpenEditorTrigger(MouseEvent e) {
        return e.getClickCount() == 2 &&
                e.getButton() == MouseEvent.BUTTON1 &&
                ((JTree) e.getSource()).getLastSelectedPathComponent() instanceof PageNode;
    }

    public void addProjectTreeBuilderListener(ProjectTreeBuilderListener listener) {
        listenerList.add(ProjectTreeBuilderListener.class, listener);
    }

    public void removeProjectTreeBuilderListener(ProjectTreeBuilderListener listener) {
        listenerList.remove(ProjectTreeBuilderListener.class, listener);
    }

    public ProjectTreeBuilderListener[] getProjectTreeBuilderListeners() {
        return listenerList.getListeners(ProjectTreeBuilderListener.class);
    }

    void fireOnTreeCreatedEvent(ProjectTreeBuilderEvent e) {
        // Guaranteed to return a non-null array
        Object[] listeners = listenerList.getListenerList();

        // Process the listeners last to first, notifying
        // those that are interested in this event
        for (int i = listeners.length - 1; i >= 0; i--) {
            if (listeners[i] == ProjectTreeBuilderListener.class) {
                ((ProjectTreeBuilderListener) listeners[i + 1]).onTreeCreated(e);
            }
        }
    }

    void fireOnTreeDestroyedEvent(ProjectTreeBuilderEvent e) {
        // Guaranteed to return a non-null array
        Object[] listeners = listenerList.getListenerList();

        // Process the listeners last to first, notifying
        // those that are interested in this event
        for (int i = listeners.length - 1; i >= 0; i--) {
            if (listeners[i] == ProjectTreeBuilderListener.class) {
                ((ProjectTreeBuilderListener) listeners[i + 1]).onTreeDestroyed(e);
            }
        }
    }

}
